package com.wenlin.myproduction.widget;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

import androidx.annotation.Nullable;

import com.wenlin.myproduction.R;
import com.wenlin.myproduction.util.Checker;
import com.wenlin.myproduction.util.UI;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 渐变色的曲线图，显示上周的学时趋势
 */
public class ChartView extends View {
    private int viewWidth = (int) UI.getPx(R.dimen.wpx1065);//直接使用固定的宽高
    private int viewHeight = (int) UI.getPx(R.dimen.wpx537);
    private Paint paint;//画笔
    private Rect rect;//算字的宽高用的
    private RectF rectFRight, rectFLeft;//画底部两个圆角用的
    private TextPaint textPaint;
    private int textColorToday, textColorAverage, textColorWeek;//三个颜色
    private int textSizeToday, textSizeAverage, textSizeWeek;//三个字号
    private int max;//最大值，至少是40，这样可以保证20min线处在下半部分
    private List<ChartBean> list;//数据集合
    private Path path;//路径
    private float chartWidth = UI.getPx(R.dimen.wpx125);//每个日期的数据的宽度，总共最多7个日期的数据
    private float baseLineBottom = UI.getPx(R.dimen.wpx120);//底部基准线到底部边界的距离——很多地方都有用到
    private float baseLineTop = UI.getPx(R.dimen.wpx80);//顶部基准线到顶部边界的距离——计算数据实际高度的时候用到
    private float baseLineStart = UI.getPx(R.dimen.wpx153);//左侧基准线到左侧的边界的距离——画日期等数据的时候用到
    private float baseLineEnd = UI.getPx(R.dimen.wpx61);//右侧基准线到右侧的边界的距离——画虚线的时候用到
    private float bitmapPaddingTop = UI.getPx(R.dimen.wpx18);//因为今日数据的圆点图片，紫色圆点并不是在图片最中间的，而是位置偏上，所以要有一个偏移值来矫正(57-21)/2
    private float radius = UI.getPx(R.dimen.wpx20);//底部圆角的半径
    private float dashWidth = UI.getPx(R.dimen.wpx20);//虚线长度
    private float todayX, todayY;//记录今日的数据点的坐标
    private Bitmap bitmap;//今日的圆点图片
    private float dotWidth = UI.getPx(R.dimen.wpx122);
    private float dotHeight = UI.getPx(R.dimen.wpx123);
    private ValueAnimator valueAnimator;//动画
    private boolean release;//是否释放
    private float valueFloat;//动画用到的

    public ChartView(Context context) {
        this(context, null);
    }

    public ChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ChartView);
        textColorToday = ta.getColor(R.styleable.ChartView_cv_text_color_today, Color.BLACK);
        textColorAverage = ta.getColor(R.styleable.ChartView_cv_text_color_average, Color.WHITE);
        textColorWeek = ta.getColor(R.styleable.ChartView_cv_text_color_week, Color.WHITE);
        textSizeToday = ta.getDimensionPixelSize(R.styleable.ChartView_cv_text_size_today, (int) UI.getPx(R.dimen.wpx40));
        textSizeAverage = ta.getDimensionPixelSize(R.styleable.ChartView_cv_text_size_average, (int) UI.getPx(R.dimen.wpx32));
        textSizeWeek = ta.getDimensionPixelSize(R.styleable.ChartView_cv_text_size_week, (int) UI.getPx(R.dimen.wpx32));
        ta.recycle();
        initialize();
    }

    /**
     * 初始化
     */
    private void initialize() {
        //画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(textColorAverage);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        //文本画笔
        textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setColor(textColorAverage);
        textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        //渐变色
        LinearGradient linearGradient = new LinearGradient(0f, 0f, viewWidth, 0f,
                Color.parseColor("#ff1dc9e3"),//蓝色
                Color.parseColor("#ff1de6ba"),//绿色
                Shader.TileMode.CLAMP
        );
        paint.setShader(linearGradient);
        //
        rect = new Rect();
        path = new Path();
        //今日的点
        bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.me_ic_purple_ball);
        bitmap = handleBitmap(bitmap, dotWidth, dotHeight);
        list = new ArrayList<>();
        //右下角和左下角两个圆角
        rectFRight = new RectF(viewWidth - 2 * radius, viewHeight - 2 * radius, viewWidth, viewHeight);
        rectFLeft = new RectF(0, viewHeight - 2 * radius, 2 * radius, viewHeight);
    }

    /**
     * 设置随机数据，随机个数，随机分钟数
     */
    @Deprecated
    public void setRandomData() {
        List<ChartBean> newList = new ArrayList<>();
        Random random = new Random();
        int t = random.nextInt(8);
        if (t > 0) {
            for (int i = 0; i < t; i++) {
                int minute = random.nextInt(100);
                if (i == 0) {
                    max = minute;
                }
//                if (i == t - 1) {
//                    minute = 20;
//                }
                newList.add(new ChartBean("11." + (10 + i), minute));//random.nextInt(40)
            }
        }
        setData(newList);
    }

    /**
     * 设置数据
     *
     * @param list 数据集合
     */
    public void setData(List<ChartBean> list) {
        if (release) return;
        max = 0;
        if (Checker.hasList(list)) {
            for (int i = 0; i < list.size(); i++) {
                max = Math.max(list.get(i).min, max);
            }
        }
        if (max < 40) max = 40;//这样一来20min线便在View中间了
        this.list = list;
        startAnimation();
    }

    /**
     * 开始动画
     */
    public void startAnimation() {
        if (release) return;
        if (Checker.hasNoList(list)) return;
        if (Checker.notNull(valueAnimator) && valueAnimator.isRunning())
            valueAnimator.cancel();
        valueAnimator = null;
        valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(animation -> {
            valueFloat = (float) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.setDuration(1000);
        valueAnimator.start();
    }

    /**
     * 释放
     */
    private void release() {
        release = true;
        if (Checker.notNull(valueAnimator)) valueAnimator.cancel();
        valueAnimator = null;
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
            bitmap = null;
        }
        if (Checker.hasList(list)) list.clear();
        list = null;
    }

    /**
     * 生成新的Bitmap图片
     *
     * @return 所求
     */
    private Bitmap handleBitmap(Bitmap bitmap, float newWidth, float newHeight) {
        Matrix matrix = new Matrix();//创建一个处理图片的类
        int width = bitmap.getWidth();//获取图片本身的大小(宽)
        int height = bitmap.getHeight();//获取图片本身的大小(高)
        float wS = newWidth / width;//缩放比---->这块注意这个是新的宽度/高度除以旧的宽度
        float hS = newHeight / height;//缩放比---->这块注意这个是新的宽度/高度除以旧的宽度
        matrix.postScale(wS, hS);//这块就是处理缩放的比例
        //matrix.setScale(sX,sY);//缩放图片的质量sX表示宽0.5就代表缩放一半,sX同样
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (release) return;
        float valueHeight = viewHeight - baseLineBottom - baseLineTop;
        if (Checker.notNull(valueAnimator) && valueAnimator.isRunning())
            valueHeight *= valueFloat;
        path.reset();
        float lastX = 0;
        float lastY = viewHeight - baseLineBottom;
        path.moveTo(lastX, lastY);
        if (Checker.hasList(list)) {
            //district
            for (int i = 0; i < list.size(); i++) {
                if (i == 0) {//如果是第一个的话，则先画线到跟第一个数据平齐的位置
                    lastY = viewHeight - baseLineBottom - list.get(i).min / (float) max * valueHeight;
                    path.lineTo(lastX, lastY);
                }
                float endX = baseLineStart + i * chartWidth + chartWidth / 2f;
                float endY = viewHeight - baseLineBottom - list.get(i).min / (float) max * valueHeight;
                float midX = (endX + lastX) / 2f;
//            float midY = (endY + lastY) / 2f;
                path.cubicTo(midX, lastY, midX, endY, endX, endY);
                lastX = endX;
                lastY = endY;
                //记录今日的紫色圆圈的位置
                if (i == list.size() - 1) {
                    todayX = endX;
                    todayY = endY;
                    path.lineTo(viewWidth, endY);
                }
            }
            path.lineTo(viewWidth, viewHeight - radius);
            path.arcTo(rectFRight, 0, 90);
            path.lineTo(radius, viewHeight);
            path.arcTo(rectFLeft, 90, 90);
            path.close();
            canvas.drawPath(path, paint);
            //画日期
            textPaint.setColor(textColorWeek);
            textPaint.setTextSize(textSizeWeek);
            for (int i = 0; i < list.size(); i++) {
                String str = list.get(i).week;
                textPaint.getTextBounds(str, 0, str.length(), rect);
                canvas.drawText(str, baseLineStart + chartWidth / 2f - rect.width() / 2f + i * chartWidth, viewHeight - baseLineBottom / 2f, textPaint);
            }
        } else {
            path.lineTo(viewWidth, viewHeight - baseLineBottom);
            path.lineTo(viewWidth, viewHeight - radius);
            path.arcTo(rectFRight, 0, 90);
            path.lineTo(radius, viewHeight);
            path.arcTo(rectFLeft, 90, 90);
            path.close();
            canvas.drawPath(path, paint);
        }
        //画20min的虚线
        float averageY = viewHeight - baseLineBottom - 20 / (float) max * valueHeight;
        float startX = baseLineStart;
        textPaint.setColor(textColorAverage);
        textPaint.setTextSize(textSizeAverage);
        while (startX < (viewWidth - baseLineEnd)) {//虚线
            canvas.drawLine(startX, averageY, startX + dashWidth / 2f, averageY, textPaint);
            startX += dashWidth;
            canvas.drawLine(startX, averageY, startX + dashWidth / 2f, averageY, textPaint);
            startX += dashWidth / 2f;
        }
        //画20min的文字
        String str = "20min";
        textPaint.getTextBounds(str, 0, str.length(), rect);
        canvas.drawText(str, baseLineStart - rect.width() - 20, averageY + rect.height() / 2f, textPaint);
        //画今日
        if (Checker.hasList(list)) {
            ChartBean today = list.get(list.size() - 1);
            if (Checker.notNull(today)) {
                canvas.drawBitmap(bitmap, todayX - bitmap.getWidth() / 2f, todayY - bitmap.getHeight() / 2f + bitmapPaddingTop, paint);
                textPaint.setColor(textColorToday);
                textPaint.setTextSize(textSizeToday);
                str = today.min + "min";
                textPaint.getTextBounds(str, 0, str.length(), rect);
                canvas.drawText(str, todayX - rect.width() / 2f, todayY - rect.height() - 5, textPaint);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
    }

    /**
     * 获取宽或者高
     *
     * @param measureSpec 测量单位
     * @param isWidSpec   是宽还是高
     * @return 所求
     */
    private int measure(int measureSpec, boolean isWidSpec) {
        int result;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = isWidSpec ? viewWidth : viewHeight;
            if (mode == MeasureSpec.AT_MOST) result = Math.min(result, size);
        }
        return result;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        release();
    }

    public static class ChartBean {
        String week;
        int min;

        public ChartBean(String week, int min) {
            this.week = week;
            this.min = min;
        }
    }
}
